#include "BaseCannon.h"
#include "BtOgrePG.h"
#include "BtOgreGP.h"
#include "BtOgreExtras.h"
#include "OgreConsole.h"
#include <Ogre.h>
#include <OgreVector3.h>
#include <OgreMath.h>
#include "BaseProjectile.h"
#include "ProjectileManager.h"
#include "GameState.hpp"
#include "PhysicsManager.h"
#include "DefaultCube.h"

using namespace Ogre;

BaseCannon::BaseCannon(Ogre::String name, Ogre::SceneManager* sceneMgr, Ogre::SceneNode* parentNode, Ogre::Vector3 cPos, int side)
{

	OgreConsole::getSingleton().print("Cannon created");
	m_pSceneMgr = sceneMgr;
	m_ParentNode = parentNode;

	m_CannonBaseNode = m_ParentNode->createChildSceneNode(name + " Base node");
	m_CannonBaseNode->setPosition(cPos);
	m_CannonBaseNode->setOrientation(Quaternion(sqrt(0.5), 0, -sqrt(0.5), 0));

	m_CannonEntity =  m_pSceneMgr->createEntity(name, "base_cannon.mesh");
	m_CannonEntity ->setMaterialName("Flat");
	m_CannonNode = m_ParentNode->createChildSceneNode(name + " Cannon node");

	m_CannonNode->attachObject(m_CannonEntity);
	m_CannonNode->scale(Vector3(0.75, 0.75, 0.75));
	m_CannonNode->setPosition(cPos);

	m_TranslateVector = Vector3::ZERO;
	m_RotateVector = Vector3::ZERO;

	canFireDelay = 10;
	canFire = true;

		m_RotateSpeed = 0.05;
	m_RotationMax = 160;
	m_RotationMin = 20;

	m_CannonSide = side;
	//0 = right, 1 = left
	if(m_CannonSide == 1){
		m_RotationMax = 160;
		m_RotationMin = 20;
		m_RotationDef = 90;
		m_CannonNode->setOrientation(Quaternion(sqrt(0.5), 0, sqrt(0.5), 0));
	}
	else{
		m_RotationMax = -20;
		m_RotationMin = -160;
		m_RotationDef = -90;
		m_CannonNode->setOrientation(Quaternion(sqrt(0.5), 0, -sqrt(0.5), 0));
	}

	cannonTimer = new Ogre::Timer(); 

	//Fire line
	m_FireLineCube = new DefaultRectangle("SimpleCubeO1" + name, Vector3(0.1, 0 , 20), Ogre::ColourValue(0.0,1.0,0.0,1.0));
	//m_FireLineCube->setCastShadows(false);
	MeshPtr mesh;
	mesh = m_FireLineCube->convertToMesh("LineMesh" + name);
	//mesh->buildEdgeList();
   // mesh->prepareForShadowVolume();

	m_LineEntity =  m_pSceneMgr->createEntity("LineEntity" +name, "LineMesh" + name);	
	m_FireLineNode = m_CannonNode->createChildSceneNode();
	m_FireLineNode->attachObject(m_LineEntity);
    m_FireLineNode->setPosition(Vector3(0.05, 0, -20));
}


BaseCannon::~BaseCannon(void)
{
}

void BaseCannon::updateCannon(double timeSinceLastFrame){


	if(!canFire){
		   if(cannonTimer->getMilliseconds() > canFireDelay){
				canFire = true;
		   }
	   }
	
		Vector3 mDestination = m_CannonTarget;                    // mDestination is the next location
		Vector3 mDirection = mDestination - m_CannonNode->_getDerivedPosition();     // B-A = A->B (see vector questions above)
		Vector3 src = m_CannonNode->_getDerivedOrientation() * -Vector3::UNIT_Z;      // Orientation from initial direction
		src.y = 0;                                                    // Ignore pitch difference angle
		mDirection.y = 0;
		src.normalise();
		Real mDistance = mDirection.normalise( );                     // Both vectors modified so renormalize them
		Quaternion quat = src.getRotationTo(mDirection);
		
		Quaternion currentOrientation = m_CannonNode->getOrientation();

		Quaternion targetingRot;

		targetingRot = currentOrientation * quat;
		Radian yRad;
		Radian pRad;
		Radian rRad;

		Ogre::Matrix3 mat;
		targetingRot.ToRotationMatrix(mat);
		mat.ToEulerAnglesYXZ(yRad, pRad, rRad);
		Degree yDeg = yRad;
		Degree xDeg = pRad;
		Degree zDeg = rRad;

		//Real yDegClamped = Math::Clamp(yDeg.valueDegrees(), (Ogre::Real)20, (Ogre::Real)160);

		if(yDeg.valueDegrees() < m_RotationMin || yDeg.valueDegrees() > m_RotationMax){

			yDeg = m_RotationDef;
			canFire = false;
		}

		//OgreConsole::getSingleton().print("Degree" + Ogre::StringConverter::toString(yDegClamped));

		mat.FromEulerAnglesYXZ((Ogre::Degree)yDeg, xDeg, zDeg);
		targetingRot.FromRotationMatrix(mat);

		//find a target
		Quaternion orientSrc = m_CannonNode->getOrientation();
        Quaternion orientDest = targetingRot;


   if (m_CannonNode->getOrientation() != targetingRot)
   {
      	Quaternion delta = Quaternion::nlerp(m_RotateSpeed, orientSrc, orientDest, true);
		m_CannonNode->setOrientation(delta);
   }
   else{
	  m_CannonNode->setOrientation(targetingRot);
	  OgreConsole::getSingleton().print("Destination reached");
   }
}

void BaseCannon::updateTarget(Ogre::Vector3 target)
{
	rotProgress = 0;
	m_CannonTarget = target;
}

void BaseCannon::fireCannon(){

	if(!canFire){
		return;
	}

	ProjectileManager::getSingletonPtr()->addBaseMissileFromCache(m_CannonNode->_getDerivedPosition(), m_CannonNode->_getDerivedOrientation(), m_CannonTarget);
	canFire = false;
	cannonTimer->reset();
}

void BaseCannon::changeDebugVisibility(){

	m_FireLineNode->flipVisibility();

}